package com.lianqi.emcpframework.ddd.gencode.creator.support.writer;

import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Modifier;

import com.lianqi.emcpframework.ddd.gencode.creator.support.meta.CreatorSetterMeta;
import com.lianqi.emcpframework.ddd.gencode.utils.TypeUtils;
import com.lianqi.emcpframework.design.support.DataOptional;
import com.squareup.javapoet.*;

import io.swagger.annotations.ApiModelProperty;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

public class DataOptionalBasedCreatorMethodWriter implements CreatorWriter {

    @Override
    public void writeTo(TypeSpec.Builder builder, MethodSpec.Builder acceptMethodBuilder,
        List<CreatorSetterMeta> setterMetas) {
        for (CreatorSetterMeta setterMeta : setterMetas) {
            String fieldName = TypeUtils.getFieldName(setterMeta.name());
            String acceptMethodName = "accept" + fieldName;
            String targetSetterName = "set" + fieldName;
            acceptMethodBuilder.addStatement("this.$L(target::$L)", acceptMethodName, targetSetterName);

            ParameterizedTypeName parameterizedTypeName =
                ParameterizedTypeName.get(ClassName.get(DataOptional.class), setterMeta.type());
            FieldSpec fieldSpec = FieldSpec.builder(parameterizedTypeName, setterMeta.name(), Modifier.PRIVATE)
                .addAnnotation(
                    AnnotationSpec.builder(Setter.class).addMember("value", "$T.PRIVATE", AccessLevel.class).build())
                .addAnnotation(
                    AnnotationSpec.builder(Getter.class).addMember("value", "$T.PUBLIC", AccessLevel.class).build())
                .addAnnotation(
                    AnnotationSpec.builder(ApiModelProperty.class).addMember("value", "$S", setterMeta.description())
                        .addMember("name", "$S", setterMeta.name()).build())
                .build();
            builder.addField(fieldSpec);

            MethodSpec methodSpec = MethodSpec.methodBuilder(setterMeta.name()).addModifiers(Modifier.PUBLIC)
                .returns(TypeVariableName.get("T")).addParameter(setterMeta.type(), setterMeta.name())
                .addStatement("this.$L = DataOptional.of($L)", setterMeta.name(), setterMeta.name())
                .addStatement("return (T) this").build();
            builder.addMethod(methodSpec);

            ParameterizedTypeName consumerTypeName =
                ParameterizedTypeName.get(ClassName.get(Consumer.class), setterMeta.type());
            MethodSpec applyMethodSpec = MethodSpec.methodBuilder(acceptMethodName).addModifiers(Modifier.PUBLIC)
                .returns(TypeVariableName.get("T")).addParameter(consumerTypeName, "consumer")
                .addCode(CodeBlock.builder().add("if(this.$L != null){ \n", setterMeta.name())
                    .add("\tconsumer.accept(this.$L.getValue());\n", setterMeta.name()).add("}\n").build())
                .addStatement("return (T) this").build();
            builder.addMethod(applyMethodSpec);
        }
    }

    @Override
    public void writeTo(TypeSpec.Builder builder, MethodSpec.Builder acceptMethodBuilder,
        List<CreatorSetterMeta> setterMetas, Map<String, AnnotationMirror> validMap) {

    }
}
